﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MandelbrotGUI.ViewModel;
using System.Windows.Input;
using System.Windows;
using System.Xml;
using System.IO;
using System.Xml.Schema;
using System.Xml.Linq;
using System.Windows.Controls;
using System.Collections.ObjectModel;
using System.Windows.Media;
using ToolsCatalog.Model;
using System.Xml.XPath;
using Microsoft.Win32;
using System.Data.Linq;
using System.Drawing.Imaging;
namespace ToolsCatalog.ViewModel
{
    class ViewModel : ViewModelBase
    {
        DelegateCommand openXMLCommand;
        DelegateCommand partOfCommand;
        DelegateCommand consistsOfCommand;

        DelegateCommand partOfDCCommand;
        DelegateCommand consistsOfDCCommand;

        DelegateCommand connectToDBCommand;
        DelegateCommand insertXML2SQLCommand;
        static int errorCount;
        Model.Catalog cat;
        Model.Catalog catDB;
        XmlDocument doc = new XmlDocument();
        XPathDocument docNav;
        string selectedToolStr;
        string path;
        List<Tool> toolsCat;
        List<Tool> toolsQueryDC;
        
        DataBase.LINQtoSQLToolsCatDataContext toolsCatDC = new DataBase.LINQtoSQLToolsCatDataContext(@"E:\FILES\DOCS\8SEM\ПРАК\TOOLSCATALOG\TOOLSCATALOG\DATABASE\TOOLSCAT.MDF");
        Table<DataBase.id_name_descr_img> id_name_descr_img;
        List<string> names;


        #region Properties
        public List<Tool> ToolsQueryDC
        {
            get { return toolsQueryDC; }
            set
            {
                toolsQueryDC = value;
                OnPropertyChanged("ToolsQueryDC");
            }
        }
        public List<Tool> ToolsCat
        {
            get { return toolsCat; }
            set
            {
                toolsCat = value;
                OnPropertyChanged("ToolsCat");
            }
        }
        public List<string> Names
        {
            get { return names; }
            set
            {
                names = value;
                OnPropertyChanged("Names");
            }
        }
        public Table<DataBase.id_name_descr_img> Id_name_descr_img
        {
            get { return id_name_descr_img; }
            set
            {
                id_name_descr_img = value;
                OnPropertyChanged("Id_name_descr_img");
            }
        }
               
        public string SelectedToolStr
        {
            get { return selectedToolStr; }
            set
            {
                selectedToolStr = value;

            }
        }

        

        public Model.Catalog CatDB
        {
            get { return catDB; }
            set
            {
                System.Diagnostics.Debug.WriteLine("Catalog Changed");
                catDB = value;
                OnPropertyChanged("CatDB");
            }

        }
        public Model.Catalog Cat
        {
            get { return cat; }
            set 
            {
                System.Diagnostics.Debug.WriteLine("Catalog Changed");
                cat = value;
                OnPropertyChanged("Cat");
            }
                
        }
       

        #endregion

        public void Query(string queryStr)
        {
            try
            {
                System.Diagnostics.Debug.WriteLine("*********" + selectedToolStr);
                XPathNavigator nav;
                XPathNodeIterator NodeIter;
                nav = docNav.CreateNavigator();
                XmlNamespaceManager m = new XmlNamespaceManager(nav.NameTable);
                m.AddNamespace("c", "http://tempuri.org/CatalogSchema.xsd");
                XPathExpression expr = nav.Compile(queryStr);
                expr.SetContext(m);
                NodeIter = nav.Select(expr);
                System.Diagnostics.Debug.WriteLine("count: " + NodeIter.Count);
                toolsCat = new List<Tool>();
                while (NodeIter.MoveNext())
                {
                    System.Diagnostics.Debug.WriteLine("Part: " + NodeIter.Current.Value);
                    ToolsCat.Add(Cat.ToolsDic[int.Parse(NodeIter.Current.Value.ToString())]);
                };
                ToolsCat = toolsCat;

            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message);
            }

        }

        public void ReadXML(string path)
        {
            XDocument doc = XDocument.Load(path);
            cat = new Model.Catalog();
            foreach (XElement el in doc.Root.Elements())
            {
                Model.Tool tool = new Model.Tool();

                System.Diagnostics.Debug.WriteLine("{0} {1} {2}",
                    el.Name.LocalName, el.Attribute("id").Value, el.Attribute("name").Value);
                tool.Id = int.Parse(el.Attribute("id").Value);
                tool.Name = el.Attribute("name").Value;

                foreach (XElement toolField in el.Elements())
                {
                    switch(toolField.Name.LocalName)
                    {
                        case "Image":
                            {
                                string im = el.Element("{http://tempuri.org/CatalogSchema.xsd}Image").Value;
                                tool.Img = ImageConverter.Base64ToImage(im);
                                break;
                            }

                            //dirtyHack
                        case "Description":
                            {
                                foreach (XElement descrStrEl in toolField.Elements())
                                {
                                    System.Diagnostics.Debug.WriteLine(descrStrEl.Value);
                                    tool.Description.Add(descrStrEl.Value);
                                }
                                break;
                            }
                        case "Params":
                            {
                                foreach (XElement parameter in toolField.Elements())
                                {
                                    System.Diagnostics.Debug.WriteLine(parameter.Value);
                                    tool.Parameters.Add(parameter.Value);
                                }
                                break;
                            }
                        case "Parts":
                            {
                                foreach (XElement part in toolField.Elements())
                                {
                                    Model.Part tpart = new Model.Part();
                                    System.Diagnostics.Debug.WriteLine
                                        ("{0} {1}", part.Attribute("partId").Value, part.Attribute("quantity").Value);
                                    tpart.Id = int.Parse(part.Attribute("partId").Value);
                                    tpart.Quantity = int.Parse(part.Attribute("quantity").Value);
                                    tool.Parts.Add(tpart);
                                }

                                break;
                            }
                        default: throw new Exception();

                    }
                }
                cat.ToolsDic.Add(tool.Id, tool);
                
                
            }
            
            Cat.BildTree();
            Cat = cat;
            

        }
        #region InsertXML2SQLCommand
        public ICommand InsertXML2SQLCommand
        {
            get
            {
                if (insertXML2SQLCommand == null)
                {
                    insertXML2SQLCommand = new DelegateCommand(InsertXML2SQL);
                }
                return insertXML2SQLCommand;
            }
        }
        public void InsertXML2SQL()
        {
            try
            {
                if (Cat != null)
                {
                    addElements();
                    addParams();
                    addParts();
                    
                }
                ConnectToDB();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }
        private void addElements()
        {
            foreach (Tool t in Cat.ToolsDicL)
            {
                DataBase.id_name_descr_img tool =
                    new DataBase.id_name_descr_img
                    {

                        id = t.Id,
                        name = t.Name,
                        description = t.DescriptionString,
                        image = ConvertImageToByteArray(t.Img, ImageFormat.Jpeg)




                    };

                toolsCatDC.id_name_descr_img.InsertOnSubmit(tool);

                try
                {
                    toolsCatDC.SubmitChanges();
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.Message);
                }

            }
        }
        private void addParams()
        {
            foreach (Tool t in Cat.ToolsDicL)
            {
                foreach (string param in t.Parameters)
                {
                    DataBase.id_parameter parameter = new DataBase.id_parameter
                    {
                        id = t.Id,
                        parameter = param
                    };
                    toolsCatDC.id_parameter.InsertOnSubmit(parameter);
                    try
                    {
                        toolsCatDC.SubmitChanges();
                    }
                    catch (Exception e)
                    {
                        MessageBox.Show(e.Message);
                    }
                }
            }
        }
        private void addParts()
        {
            foreach (Tool t in Cat.ToolsDicL)
            {
                foreach(Part part in t.Parts)
                {
                    DataBase.id_part_count partDB = new DataBase.id_part_count
                    {
                        id = t.Id,
                        part = part.Id,
                        count = part.Quantity
                    };
                    toolsCatDC.id_part_count.InsertOnSubmit(partDB);
                    try
                    {
                        toolsCatDC.SubmitChanges();
                    }
                    catch (Exception e)
                    {
                        MessageBox.Show(e.Message);
                    }
                }
            }
        }
        private Binary ConvertImageToByteArray(System.Drawing.Image imageToConvert,
            ImageFormat formatOfImage)
        {
            byte[] Ret;

            try
            {

                using (MemoryStream ms = new MemoryStream())
                {
                    imageToConvert.Save(ms, formatOfImage);
                    Ret = ms.ToArray();
                }
            }
            catch (Exception) { throw; }

            return new  Binary(Ret);
        }
        private System.Drawing.Image getImageFromBinary(byte[] array)
        {
            if (array == null)
                return ToolsCatalog.Properties.Resources.NoImage;
            using (MemoryStream ms = new MemoryStream(array, 0, array.Length))
            {
                
                ms.Write(array, 0, array.Length);

                System.Drawing.Image img = System.Drawing.Image.FromStream(ms, true);
                return img;
                // work with image here.

                // You'll need to keep the MemoryStream open for
                // as long as you want to work with your new image.

            }
        }
        #endregion
        #region ConnectToDBCommand
        public ICommand ConnectToDBCommand
        {
            get
            {
                if (connectToDBCommand == null)
                {
                    connectToDBCommand = new DelegateCommand(ConnectToDB);
                }
                return connectToDBCommand;
            }
        }
        public void ConnectToDB()
        {
            try
            {
                //db = new DataContext(@"E:\files\docs\8sem\прак\ToolsCatalog\ToolsCatalog\DataBase\ToolsCat.mdf");
                //toolsCatDC.id_name_descr_img
                //List<string> tmpNames = new List<string>();
                //Id_name_descr_img = toolsCatDC.id_name_descr_img;
                catDB = new Catalog();
                foreach (DataBase.id_name_descr_img element in toolsCatDC.id_name_descr_img)
                {
                    Tool t = new Tool();
                    t.Name = element.name;
                    t.Id = element.id;
                    t.Description.Add(element.description);

                    if (element.image == null) t.Img = getImage("");
                    else t.Img = ImageConverter.Base64ToImage(
                        System.Convert.ToBase64String(element.image.ToArray()));
                    

                    var paramsQuery =
                        (from parameter in toolsCatDC.id_parameter
                        where parameter.id == t.Id
                        select  parameter.parameter);
                    t.Parameters = paramsQuery.ToList<string>();
                    
                    var partsQuery =
                        from part in toolsCatDC.id_part_count
                        where part.id == t.Id
                        select new { part.part, part.count };
                    foreach(var part in partsQuery)
                    {
                        Part tPart = new Part();
                        tPart.Id = part.part;
                        tPart.Quantity = part.count;
                        t.Parts.Add(tPart);
                    }
                    catDB.ToolsDic.Add(t.Id, t);
                    //tmpNames.Add(id_name.name);
                }
                catDB.BildTree();
                CatDB = catDB;
                
                
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }
        #endregion
        public System.Drawing.Image getImage(string imgData)
        {
            if (imgData == "") return ToolsCatalog.Properties.Resources.NoImage;
            else
            {
                System.Drawing.Image tmpImg =   ImageConverter.Base64ToImage(imgData);
                if (tmpImg == null) return ToolsCatalog.Properties.Resources.NoImage;
                else return tmpImg;
            }
        }

        #region ConsistsOfCommand
        public ICommand ConsistsOfCommand
        {
            get
            {
                if (consistsOfCommand == null)
                {
                    consistsOfCommand = new DelegateCommand(ConsistsOf);
                }
                return consistsOfCommand;
            }
        }
        public void ConsistsOf()
        {
            String strExpression = "//c:Part/@partId[ancestor::c:Tool/@id=" + selectedToolStr + "]";
            Query(strExpression);
        }
        bool CanConsistsOf
        {
            get
            {
                if (Cat == null) return false;
                return true;
            }
        }
        #endregion
        #region PartOfCommand
        public ICommand PartOfCommand
        {
            get
            {
                if (partOfCommand == null)
                {
                    partOfCommand = new DelegateCommand(PartOf);
                }
                return partOfCommand;
            }
        }
        public void PartOf()
        {
            String strExpression = "//c:Tool[descendant::c:Part/@partId=" + selectedToolStr + "]/@id";
            // = "//c:Part/@partId[ancestor::c:Tool/@id=" + selectedToolStr + "]";
            Query(strExpression);
        }
        bool CanPartOf
        {
            get
            {
                if (Cat == null) return false;
                return true;
            }
        }
        
        #endregion


        #region ConsistsOfDCCommand
        public ICommand ConsistsOfDCCommand
        {
            get
            {
                if (consistsOfDCCommand == null)
                {
                    consistsOfDCCommand = new DelegateCommand(ConsistsOfDC);
                }
                return consistsOfDCCommand;
            }
        }
        public void ConsistsOfDC()
        {
            ToolsQueryDC = getChildren(int.Parse(selectedToolStr));
        }
        public List<Tool> getChildren(int toolID)
        {
            List<Tool> tools = new List<Tool>();
            var partOfQuery =
                (from element in toolsCatDC.id_part_count
                 where element.id == toolID
                 select element.part);
            foreach (var element in partOfQuery)
            {
                tools.Add(catDB.ToolsDic[element]);
            }
            List<Tool> tmpTools = new List<Tool>();
            foreach (Tool tool in tools)
            {
                tmpTools.AddRange(getChildren(tool.Id));
            }
            tools.AddRange(tmpTools);
            return tools;
        }
        bool CanConsistsOfDC
        {
            get
            {
                if (Cat == null) return false;
                return true;
            }
        }
        #endregion
        #region PartOfDCCommand
        public ICommand PartOfDCCommand
        {
            get
            {
                if (partOfDCCommand == null)
                {
                    partOfDCCommand = new DelegateCommand(PartOfDC);
                }
                return partOfDCCommand;
            }
        }
        public void PartOfDC()
        {
            ToolsQueryDC = getAncestors(int.Parse(selectedToolStr));
        }
        bool CanPartOfDC
        {
            get
            {
                if (Cat == null) return false;
                return true;
            }
        }
        public List<Tool> getAncestors(int toolID)
        {
            List<Tool> tools = new List<Tool>();
            var partOfQuery =
                (from element in toolsCatDC.id_part_count
                 where element.part == toolID
                 select element.id);
            foreach (var element in partOfQuery)
            {
                tools.Add(catDB.ToolsDic[element]);
            }
            List<Tool> tmpTools = new List<Tool>();
            foreach (Tool tool in tools)
            {
                tmpTools.AddRange(getAncestors(tool.Id));
            }
            tools.AddRange(tmpTools);
            return tools;
        }
        #endregion


        #region OpenXMLCommand
        public ICommand OpenXMLCommand
        {
            get
            {
                if (openXMLCommand == null)
                {
                    openXMLCommand = new DelegateCommand(OpenXML);
                }
                return openXMLCommand;
            }
        }
        public void OpenXML()
        {
            OpenFileDialog ofd = new OpenFileDialog();
            if (ofd.ShowDialog() == true)
            {
                path = ofd.FileName;
                Validate();
            }
            
            
        }
        #endregion
        #region ValidateCommand
        

        static void ValidationEventHandler(object sender, ValidationEventArgs e)
        {
            MessageBox.Show(e.Message);
            Console.WriteLine("{0}: {1}", e.Severity, e.Message);
            errorCount++;
        }

        public void Validate()
        {
            try
            {

                XmlReaderSettings xrs = new XmlReaderSettings();
                xrs.ValidationType = ValidationType.Schema;
                xrs.ValidationEventHandler += new ValidationEventHandler(ValidationEventHandler);

                using (StreamReader sr = new StreamReader("CatalogSchema.xsd"))
                {
                    XmlSchema schema = XmlSchema.Read(sr, null);
                    xrs.Schemas.Add(schema);
                }

                XmlReader reader = XmlReader.Create(path, xrs);
                errorCount = 0;
                
                int i = 0;
                while (reader.Read())
                    i++;
                if (errorCount == 0)
                {
                    docNav = new XPathDocument(@path);
                    ReadXML(path);

                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }
        bool CanValidate
        {
            get
            {
                return true;
            }
        }
        #endregion



       
    }
}
